namespace Microsoft.VisualStudio.EnterpriseTools.OperationDesigner
{
    using Microsoft.VisualStudio.EnterpriseTools.ArtifactModel.Clr;
    using Microsoft.VisualStudio.EnterpriseTools.Shell;
    using Microsoft.VisualStudio.Modeling;
    using Microsoft.VisualStudio.Modeling.ArtifactMapper;
    using Microsoft.VisualStudio.VirtualTreeGrid;
    using System;
    using System.ComponentModel;
    using System.Globalization;

    public class ModifierColumn : ColumnDescriptor
    {
        private ClrElement currentElement;
        private OperationDesignerInPlaceEditCombo memberCombo;
        private TypeConverter memberTypeConverter;
        private OperationDesignerInPlaceEditCombo parameterCombo;
        private TypeConverter parameterTypeConverter;

        public ModifierColumn() : base(ClrBranchStrings.GetString("ModifierColumnTitle"))
        {
        }

        public override void AddEventHandlers(Store store)
        {
            store.EventManagerDirectory.ElementAttributeChanged.Add(store.MetaDataDirectory.FindMetaAttribute(ClrParameter.ParameterKindMetaAttributeGuid), new ElementAttributeChangedEventHandler(this.OnModifierChanged));
            store.EventManagerDirectory.ElementAttributeChanged.Add(store.MetaDataDirectory.FindMetaAttribute(Member.AccessModifierMetaAttributeGuid), new ElementAttributeChangedEventHandler(this.OnModifierChanged));
            store.EventManagerDirectory.ElementAttributeChanged.Add(store.MetaDataDirectory.FindMetaAttribute(ClrType.AccessModifierMetaAttributeGuid), new ElementAttributeChangedEventHandler(this.OnModifierChanged));
        }

        private void EnsureTypeConverters(ClrElement element)
        {
            if (((this.memberTypeConverter == null) || (this.parameterTypeConverter == null)) || (this.currentElement != element))
            {
                this.currentElement = element;
                this.memberTypeConverter = new ClrElementEnumTypeConverter(typeof(AccessModifier), element);
                this.parameterTypeConverter = new ClrElementEnumTypeConverter(typeof(ParameterKind), element);
            }
        }

        public override object GetInPlaceEdit(object component, ref string alternateText)
        {
            if ((component is Member) || (component is ClrDelegate))
            {
                this.EnsureTypeConverters((ClrElement) component);
                if (this.memberCombo == null)
                {
                    this.memberCombo = new OperationDesignerInPlaceEditCombo(this, component);
                    this.memberCombo.DismissLabelEditOnDropDownClose = true;
                    this.memberCombo.Flags &= ~VirtualTreeInPlaceControlFlags.DisposeControl;
                }
                else
                {
                    this.memberCombo.CurrentPropertyDescriptor = this;
                    if (this.memberCombo.CurrentInstance != component)
                    {
                        this.memberCombo.CurrentInstance = component;
                    }
                    this.memberCombo.Items.Clear();
                }
                foreach (object obj2 in this.memberTypeConverter.GetStandardValues())
                {
                    this.memberCombo.Items.Add(this.memberTypeConverter.ConvertTo(null, CultureInfo.CurrentCulture, obj2, typeof(string)));
                }
                return this.memberCombo;
            }
            ClrParameter element = component as ClrParameter;
            if (element == null)
            {
                throw new ArgumentException("component");
            }
            this.EnsureTypeConverters(element);
            if (this.parameterCombo == null)
            {
                this.parameterCombo = new OperationDesignerInPlaceEditCombo(this, component);
                this.parameterCombo.DismissLabelEditOnDropDownClose = true;
                this.parameterCombo.Flags &= ~VirtualTreeInPlaceControlFlags.DisposeControl;
            }
            else
            {
                this.parameterCombo.CurrentPropertyDescriptor = this;
                if (this.parameterCombo.CurrentInstance != component)
                {
                    this.parameterCombo.CurrentInstance = component;
                }
                this.parameterCombo.Items.Clear();
            }
            foreach (object obj3 in this.parameterTypeConverter.GetStandardValues())
            {
                this.parameterCombo.Items.Add(this.parameterTypeConverter.ConvertTo(null, CultureInfo.CurrentCulture, obj3, typeof(string)));
            }
            return this.parameterCombo;
        }

        public override object GetValue(object component)
        {
            Member element = component as Member;
            if (element != null)
            {
                if (element.ClrType is ClrInterface)
                {
                    return string.Empty;
                }
                this.EnsureTypeConverters(element);
                ClrMethod method = element as ClrMethod;
                if (method != null)
                {
                    SupportedLanguageSet languageType = element.LanguageType;
                    if (method.IsDestructor)
                    {
                        return null;
                    }
                }
                return this.memberTypeConverter.ConvertTo(null, CultureInfo.CurrentCulture, element.AccessModifier, typeof(string));
            }
            ClrParameter parameter = component as ClrParameter;
            if (parameter != null)
            {
                this.EnsureTypeConverters(parameter);
                return this.parameterTypeConverter.ConvertTo(null, CultureInfo.CurrentCulture, parameter.ParameterKind, typeof(string));
            }
            ClrDelegate delegate2 = component as ClrDelegate;
            if (delegate2 != null)
            {
                this.EnsureTypeConverters(delegate2);
                return this.memberTypeConverter.ConvertTo(null, CultureInfo.CurrentCulture, delegate2.AccessModifier, typeof(string));
            }
            return string.Empty;
        }

        public override OperationDesignerValueSupportedStates GetValueSupported(object component)
        {
            bool flag = false;
            ClrMethod method = component as ClrMethod;
            if ((method != null) && method.IsDestructor)
            {
                flag = false;
            }
            else if (((component is Member) && !(((Member) component).ClrType is ClrInterface)) || (component is ClrDelegate))
            {
                flag = true;
            }
            else
            {
                ClrParameter parameter = component as ClrParameter;
                if ((parameter != null) && !parameter.IsRemoved)
                {
                    flag = true;
                }
            }
            if (!flag)
            {
                return OperationDesignerValueSupportedStates.Unsupported;
            }
            return OperationDesignerValueSupportedStates.Supported;
        }

        private void OnModifierChanged(object sender, ElementAttributeChangedEventArgs e)
        {
            if (base.Host != null)
            {
                base.Host.Refresh(e.ModelElement);
            }
        }

        public override void RemoveEventHandlers(Store store)
        {
            store.EventManagerDirectory.ElementAttributeChanged.Remove(store.MetaDataDirectory.FindMetaAttribute(ClrParameter.ParameterKindMetaAttributeGuid), new ElementAttributeChangedEventHandler(this.OnModifierChanged));
            store.EventManagerDirectory.ElementAttributeChanged.Remove(store.MetaDataDirectory.FindMetaAttribute(Member.AccessModifierMetaAttributeGuid), new ElementAttributeChangedEventHandler(this.OnModifierChanged));
            store.EventManagerDirectory.ElementAttributeChanged.Remove(store.MetaDataDirectory.FindMetaAttribute(ClrType.AccessModifierMetaAttributeGuid), new ElementAttributeChangedEventHandler(this.OnModifierChanged));
        }

        public override void SetValue(object component, object value)
        {
            if ((component is Member) || (component is ClrDelegate))
            {
                this.EnsureTypeConverters((ClrElement) component);
                if (this.memberTypeConverter.CanConvertFrom(value.GetType()))
                {
                    try
                    {
                        object obj2 = this.memberTypeConverter.ConvertFrom(null, CultureInfo.CurrentCulture, value);
                        if (obj2 != null)
                        {
                            AccessModifier modifier = (AccessModifier) obj2;
                            if (component is Member)
                            {
                                Member member = (Member) component;
                                if (modifier == member.AccessModifier)
                                {
                                    return;
                                }
                                using (Transaction transaction = member.Store.TransactionManager.BeginTransaction(ClrBranchStrings.GetString("ChangeModifierUndoText")))
                                {
                                    member.AccessModifier = modifier;
                                    transaction.Commit();
                                    return;
                                }
                            }
                            ClrDelegate delegate2 = (ClrDelegate) component;
                            if (modifier != delegate2.AccessModifier)
                            {
                                using (Transaction transaction2 = delegate2.Store.TransactionManager.BeginTransaction(ClrBranchStrings.GetString("ChangeModifierUndoText")))
                                {
                                    delegate2.AccessModifier = modifier;
                                    transaction2.Commit();
                                }
                            }
                        }
                    }
                    catch (NotSupportedException)
                    {
                    }
                }
            }
            else
            {
                ClrParameter element = component as ClrParameter;
                if (element != null)
                {
                    this.EnsureTypeConverters(element);
                    if (this.parameterTypeConverter.CanConvertFrom(value.GetType()))
                    {
                        bool flag = true;
                        try
                        {
                            object obj3 = this.parameterTypeConverter.ConvertFrom(null, CultureInfo.CurrentCulture, value);
                            if (obj3 != null)
                            {
                                ParameterKind kind = (ParameterKind) obj3;
                                if (kind != element.ParameterKind)
                                {
                                    if ((element.LanguageType == SupportedLanguageSet.VisualBasic) && (kind == ParameterKind.ParamArray))
                                    {
                                        flag = false;
                                    }
                                    using (Transaction transaction3 = element.Store.TransactionManager.BeginTransaction(ClrBranchStrings.GetString("ChangeModifierUndoText")))
                                    {
                                        element.ParameterKind = kind;
                                        transaction3.Commit();
                                    }
                                }
                            }
                        }
                        catch (NotSupportedException)
                        {
                        }
                        catch (ArtifactHandlerException)
                        {
                            if (flag)
                            {
                                throw;
                            }
                            PackageUtility.ShowError(element.Store, ClrBranchStrings.GetString("ParamArrayErrorForUndefinedType"));
                        }
                    }
                }
            }
        }

        public override string Category
        {
            get
            {
                return ClrBranchStrings.GetString("ModifierColumnTitle");
            }
        }

        public override TypeConverter Converter
        {
            get
            {
                if (this.parameterTypeConverter == null)
                {
                    return base.Converter;
                }
                return this.parameterTypeConverter;
            }
        }
    }
}

